// 回调生成器的外部包装。 用户可以自定义
//`_.iteratee`，如果他们想要其他谓词/ iteratee速记样式。
//此抽象隐藏仅内部的argCount参数

import identity from "./identity";
import isFunction from "../object/isFunction";
import isObject from "../object/isObject";
import isArray from "../object/isArray";
import matcher from "../object/matcher";
import property from "../object/property";


// 生成可应用于集合中的每个元素的回调。_.iteratee支持许多常见回调用例的简写语法。根据值的类型，_.iteratee 将返回
let builtinIteratee

export default function iteratee(value, context) {
  return cb(value, context, Infinity);
}

//一个内部函数来生成可应用于每个回调的回调
//集合中的元素，返回所需的结果，即`identity`，
//任意回调，属性匹配器或属性访问器。
export const cb = function (value, context?, argCount?): Function {
  if (iteratee !== builtinIteratee) return iteratee(value, context)
  if (value == null) return identity;
  if (isFunction(value)) {
    return optimizeCb(value, context, argCount)
  }
  if (isObject(value) && !isArray(value)) {
    return matcher(value)
  }
  return property(value);
}



//内部函数返回有效的版本（对于当前引擎）
//传入的回调，将在其他Underscore中重复应用
// 功能。
export function optimizeCb<T>(func: T): T;
export function optimizeCb<T>(func: T, context?: any, argCount?: number | null): <C, R>(value: C) => R;
export function optimizeCb<T>(func: T, context?: any, argCount?: number | null): <C, R>(value: C, index: string | number, collection: C[]) => R;
export function optimizeCb<T>(func: T, context?: any, argCount?: number | null): <C, R>(accumulator: C, value: C, index: string | number, collection: C[]) => R;
export function optimizeCb<T>(func: T, context?: any, argCount?: number | null): <C>() => C;
export function optimizeCb(func, context?, argCount?) {
  if (context === void 0) return func
  switch (argCount == null ? 3 : argCount) {
    case 1:
      return function <T, R>(value: T): R {
        return func.call(context, value)
      }
    case 3:
      return function (value, index, collection) {
        return func.call(context, value, index, collection)
      }
    case 4:
      return function (accumulator, value, index, collection) {
        return func.call(context, accumulator, value, index, collection)
      }
  }
  return function () {
    return func.apply(context, arguments)
  }
}